package ch.ethz.fcl.metrobuzz.algorithm.voronoi.Fortune;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.controller.MBController;
import ch.ethz.fcl.metrobuzz.controller.external.ActionEvent;
import ch.ethz.fcl.metrobuzz.render.MBRenderer;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Rectangle;
import ch.ethz.fcl.metrobuzz.spatialindex.object3d.Point3D;
import ch.ethz.fcl.metrobuzz.tools.MBGL;
import ch.ethz.fcl.metrobuzz.viewer.MBViewer;
import ch.ethz.fcl.metrobuzz.viewer.MBViewer.ProjectionType;

/**
 * Test code of how to work with Fortune's voronoi algorithm
 * 
 * @author ZengWei
 * 
 */
public class FortuneVoronoiTest {
	private MBContainer container;

	Voronoi voronoi = new Voronoi(0.000000001);
	float minX = -0.3f, minY = -0.3f, maxX = 0.3f, maxY = 0.3f;
	List<GraphEdge> edges = null;

	List<Float> xValues, yValues;

	public static void main(String[] args) {
		new FortuneVoronoiTest().run();
	}

	public FortuneVoronoiTest() {
		init();
	}

	private void run() {
		while (!Display.isCloseRequested()) {
			GL11.glPushMatrix();
			container.getViewer().update();

			container.getControl().update();

			update();
			render();

			GL11.glPopMatrix();

			Display.update();
			Display.sync(32);
		}
		Display.destroy();
		System.exit(0);
	}

	private void init() {
		xValues = new ArrayList<Float>();
		yValues = new ArrayList<Float>();

		container = new MBContainer();

		MBViewer view = new MBViewer(ProjectionType.Perspective, container);

		new MBRenderer(container);

		int screenWidth = Display.getDesktopDisplayMode().getWidth();
		int screenHeight = Display.getDesktopDisplayMode().getHeight();
		view.createDisplay(screenWidth, screenHeight, screenWidth, screenHeight,
				" Fortune voronoi test");
		view.getCamera().initDistance(1.0f);
		view.getCamera().disablePan();

		new MBController(container);
	}

	private void update() {
		ActionEvent action = container.getControl().getMouseListener()
				.getRightMouse();

		if (action.getAction() == ActionEvent.ACTION_DOWN) {
			Point3D clickPoint = container
					.getViewer()
					.getProjection()
					.getWorldCoord(
							new Point2D(action.getEventX(), action.getEventY()),
							0);

			xValues.add(clickPoint.getX());
			yValues.add(clickPoint.getY());

			edges = voronoi.generateVoronoi(toDoubleArray(xValues),
					toDoubleArray(yValues), minX, maxX, minY, maxY);
		}
	}

	private void render() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		GL11.glClearColor(1, 1, 1, 1);

		MBGL.enableBlend();

		GL11.glPointSize(5.0f);
		GL11.glColor4f(1, 0, 0, 1);
		GL11.glBegin(GL11.GL_POINTS);
		for (int i = 0; i < xValues.size(); i++)
			GL11.glVertex2f(xValues.get(i), yValues.get(i));
		GL11.glEnd();

		GL11.glLineWidth(1.0f);
		GL11.glColor4f(0, 0, 1, 1);
		if (edges != null) {
			GL11.glBegin(GL11.GL_LINES);
			for (int i = 0; i < edges.size(); i++) {
				GL11.glVertex2d(edges.get(i).x1, edges.get(i).y1);
				GL11.glVertex2d(edges.get(i).x2, edges.get(i).y2);
			}
			GL11.glEnd();
		}

		new Rectangle(minX, minY, maxX, maxY).render();
		MBGL.disableBlend();
	}

	private double[] toDoubleArray(List<Float> in) {
		double[] out = new double[in.size()];

		for (int i = 0; i < in.size(); i++) {
			out[i] = in.get(i);
		}

		return out;
	}
}
